package com.mihuo.util;

import lombok.extern.slf4j.Slf4j;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.SecureRandom;
import java.util.Base64;

/**
 * AES 对称加密工具类
 * 支持 ECB 和 CBC 两种工作模式，提供完整的加密解密功能
 * 
 * @author mihuo
 * @date 2025-09-27
 * @version 2.0
 */
@Slf4j
public class AESUtil {
    
    // 加密算法定义
    private static final String AES = "AES";
    private static final String ECB_MODE = "AES/ECB/PKCS5Padding";
    private static final String CBC_MODE = "AES/CBC/PKCS5Padding";
    private static final String SECRET_KEY = "uWW1ZdU/M/nUnAgiw0iC9Q==";
    private static final String SECRET_IV = "xM5GTf3XAZ7fe/UV5CJPbg==";

    // 默认密钥和IV长度
    private static final int KEY_SIZE = 128;
    private static final int IV_LENGTH = 16;
    
    /**
     * 生成随机 AES 密钥（Base64编码）
     * 
     * @return Base64编码的密钥字符串
     * @throws Exception 密钥生成异常
     */
    public static String generateKey() throws Exception {
        KeyGenerator keyGenerator = KeyGenerator.getInstance(AES);
        keyGenerator.init(KEY_SIZE, new SecureRandom());
        SecretKey secretKey = keyGenerator.generateKey();
        return Base64.getEncoder().encodeToString(secretKey.getEncoded());
    }
    
    /**
     * 生成随机初始化向量（IV）
     * 
     * @return Base64编码的IV字符串
     */
    public static String generateIV() {
        byte[] iv = new byte[IV_LENGTH];
        new SecureRandom().nextBytes(iv);
        return Base64.getEncoder().encodeToString(iv);
    }
    
    /**
     * ECB 模式加密（无需IV）
     * 
     * @param plaintext 明文
     * @param base64Key Base64编码的密钥
     * @return Base64编码的密文
     * @throws Exception 加密异常
     */
    public static String encryptECB(String plaintext, String base64Key) throws Exception {
        validateInput(plaintext, base64Key);
        
        byte[] keyBytes = Base64.getDecoder().decode(base64Key);
        SecretKeySpec secretKey = new SecretKeySpec(keyBytes, AES);
        
        Cipher cipher = Cipher.getInstance(ECB_MODE);
        cipher.init(Cipher.ENCRYPT_MODE, secretKey);
        
        byte[] encrypted = cipher.doFinal(plaintext.getBytes(StandardCharsets.UTF_8));
        return Base64.getEncoder().encodeToString(encrypted);
    }
    
    /**
     * ECB 模式解密
     * 
     * @param encryptedText Base64编码的密文
     * @param base64Key Base64编码的密钥
     * @return 解密后的明文
     * @throws Exception 解密异常
     */
    public static String decryptECB(String encryptedText, String base64Key) throws Exception {
        validateInput(encryptedText, base64Key);
        
        byte[] keyBytes = Base64.getDecoder().decode(base64Key);
        SecretKeySpec secretKey = new SecretKeySpec(keyBytes, AES);
        
        Cipher cipher = Cipher.getInstance(ECB_MODE);
        cipher.init(Cipher.DECRYPT_MODE, secretKey);
        
        byte[] decoded = Base64.getDecoder().decode(encryptedText);
        byte[] decrypted = cipher.doFinal(decoded);
        return new String(decrypted, StandardCharsets.UTF_8);
    }
    
    /**
     * CBC 模式加密（需要IV）
     * 
     * @param plaintext 明文
     * @param base64Key Base64编码的密钥
     * @param base64IV Base64编码的初始化向量
     * @return Base64编码的密文
     * @throws Exception 加密异常
     */
    public static String encryptCBC(String plaintext, String base64Key, String base64IV) throws Exception {
        validateInput(plaintext, base64Key, base64IV);
        
        byte[] keyBytes = Base64.getDecoder().decode(base64Key);
        byte[] ivBytes = Base64.getDecoder().decode(base64IV);
        
        SecretKeySpec secretKey = new SecretKeySpec(keyBytes, AES);
        IvParameterSpec ivSpec = new IvParameterSpec(ivBytes);
        
        Cipher cipher = Cipher.getInstance(CBC_MODE);
        cipher.init(Cipher.ENCRYPT_MODE, secretKey, ivSpec);
        
        byte[] encrypted = cipher.doFinal(plaintext.getBytes(StandardCharsets.UTF_8));
        return Base64.getEncoder().encodeToString(encrypted);
    }
    
    /**
     * CBC 模式解密
     * 
     * @param encryptedText Base64编码的密文
     * @param base64Key Base64编码的密钥
     * @param base64IV Base64编码的初始化向量
     * @return 解密后的明文
     * @throws Exception 解密异常
     */
    public static String decryptCBC(String encryptedText, String base64Key, String base64IV) throws Exception {
        validateInput(encryptedText, base64Key, base64IV);
        
        byte[] keyBytes = Base64.getDecoder().decode(base64Key);
        byte[] ivBytes = Base64.getDecoder().decode(base64IV);
        
        SecretKeySpec secretKey = new SecretKeySpec(keyBytes, AES);
        IvParameterSpec ivSpec = new IvParameterSpec(ivBytes);
        
        Cipher cipher = Cipher.getInstance(CBC_MODE);
        cipher.init(Cipher.DECRYPT_MODE, secretKey, ivSpec);
        
        byte[] decoded = Base64.getDecoder().decode(encryptedText);
        byte[] decrypted = cipher.doFinal(decoded);
        return new String(decrypted, StandardCharsets.UTF_8);
    }
    
    /**
     * 验证输入参数（ECB模式）
     */
    private static void validateInput(String text, String key) {
        if (text == null || text.trim().isEmpty()) {
            throw new IllegalArgumentException("加密文本不能为空");
        }
        if (key == null || key.trim().isEmpty()) {
            throw new IllegalArgumentException("密钥不能为空");
        }
    }
    
    /**
     * 验证输入参数（CBC模式）
     */
    private static void validateInput(String text, String key, String iv) {
        validateInput(text, key);
        if (iv == null || iv.trim().isEmpty()) {
            throw new IllegalArgumentException("初始化向量(IV)不能为空");
        }
    }

    /**
     * 项目内加密用这个,使用CBC模式
     * @param data
     * @return
     */
    public static String encrypt(String data) {
        try {
            return encryptCBC(data,SECRET_KEY,SECRET_IV);
        }catch (Exception e){
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 项目内解密用这个,使用CBC模式
     * @param encodeData
     * @return
     */
    public static String decrypt(String encodeData) {
        try {
            return decryptCBC(encodeData,SECRET_KEY,SECRET_IV);
        }catch (Exception e){
            log.error("密码解密失败：{}",e.getMessage());
        }
        return null;
    }

    /**
     * 测试用例
     */
    public static void main(String[] args) {
        try {
            // 生成密钥和IV
            String key = generateKey();
            String iv = generateIV();
            String testData = "123456";
            
            log.info("原始数据: {}", testData);
            log.info("生成密钥: {}", key);
            log.info("生成IV: {}", iv);
            
            // ECB模式测试
            String ecbEncrypted = encryptECB(testData, key);
            String ecbDecrypted = decryptECB(ecbEncrypted, key);
            log.info("ECB加密结果: {}", ecbEncrypted);
            log.info("ECB解密结果: {}", ecbDecrypted);
            
            // CBC模式测试
            String cbcEncrypted = encryptCBC(testData, key, iv);
            String cbcDecrypted = decryptCBC(cbcEncrypted, key, iv);
            log.info("CBC加密结果: {}", cbcEncrypted);
            log.info("CBC解密结果: {}", cbcDecrypted);
            
            log.info(AESUtil.encrypt("123456"));
            
        } catch (Exception e) {
            log.error("AES加解密测试异常", e);
        }
    }
}